package surface;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;

import javax.swing.JPanel;

import shape.Shape;
import storage.CanvasMemento;
import storage.CareTaker;
import storage.Memento;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Singleton;

@SuppressWarnings("serial")
@Singleton
public class CanvasImpl extends JPanel implements Canvas {

	private List<Shape> shapes = Lists.newArrayList();

	private int startX, startY, endX, endY;

	private final List<CanvasObserver> observers = Lists.newArrayList();

	private final CareTaker careTaker;

	@Inject
	public CanvasImpl(final CareTaker careTaker) {
		this.careTaker = careTaker;

		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				startX = e.getX();
				startY = e.getY();
			}
		});

		addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent e) {
				endX = e.getX();
				endY = e.getY();
				notifyObservers(true);
			}
		});
		
		setBackground(Color.white);
	}

	@Override
	public CanvasMemento saveMemento() {
		return new CanvasMemento(ImmutableList.copyOf(shapes));
	}

	@Override
	public void restoreMemento(final Memento memento) {
		shapes = Lists.newArrayList();
		shapes.addAll(memento.getShapes());
		notifyObservers(false);
		repaint();
	}

	@Override
	public void addShape(final Shape shape) {
		shapes.add(shape);
		notifyObservers(false);
		careTaker.add(saveMemento());
		repaint();
	}

	@Override
	public Shape getShape(final int index) {
		return shapes.get(index);
	}

	@Override
	public void updateShape(final int index, final Shape shape) {
		shapes.set(index, shape);
		notifyObservers(false);
		careTaker.add(saveMemento());
		repaint();
	}

	@Override
	public void displayShapes() {
		int i = 0;
		for (Shape shape : shapes) {
			System.out.println("Shape : " + ++i);
			shape.draw();
		}
	}

	@Override
	public void attach(final CanvasObserver observer) {
		observers.add(observer);
	}

	@Override
	public void detach(final CanvasObserver observer) {
		observers.remove(observer);
	}

	@Override
	public void notifyObservers(boolean mouseReleased) {
		int i = 0;
		for (CanvasObserver observer : observers) {
			System.out.println("Notifying observer: " + ++i);
			observer.update(mouseReleased);
		}
	}

	@VisibleForTesting
	public List<CanvasObserver> getObservers() {
		return observers;
	}

	public List<Shape> getShapes() {
		return shapes;
	}

	public int getStartX() {
		return startX;
	}

	public int getStartY() {
		return startY;
	}

	public int getEndX() {
		return endX;
	}

	public int getEndY() {
		return endY;
	}
	
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		for (Shape shape : shapes) {
			shape.paintShape(g);
		}
	}
}
